package com.chisheng.config;

import com.chisheng.aspect.LogAspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.chisheng.service")
@SuppressWarnings("all")  /* Application context not configured for this file */
public class AopDemoConfiguration {

    /* 声明式切面的使用
     * 1) 通过 @EnableAspectJAutoProxy 注解开启声明式切面
     * 2) 自定义切面类和通知方法并使用 @Aspect 标注声明切面类
     * 3) 将切面类注入到容器中（如 @Bean 方式） */

    /* @EnableAspectJAutoProxy 工作细节 */

    /* @Import(AspectJAutoProxyRegistrar.class) */

    /* class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
     *      public void registerBeanDefinitions(...) {
     * 		    AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
     *          ...
     *      }
     * } */

    /* public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
     * 		return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
     * } */

    /* public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {
     *      return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
     * } */

    /* private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
     *      ...
     * 		RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
     * 		beanDefinition.setSource(source);
     * 		beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
     * 		beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
     * 		registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
     * 		return beanDefinition;
     * } */

    /* public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
     *      protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
     * 		    super.initBeanFactory(beanFactory);
     * 		    if (this.aspectJAdvisorFactory == null) {
     * 			    this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
     *          }
     *
     * 		    this.aspectJAdvisorsBuilder = new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
     *    }
     * } */

    /* public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {
     *      public void setBeanFactory(BeanFactory beanFactory) {
     * 		    super.setBeanFactory(beanFactory);
     * 		    ...
     * 		    initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
     * 		}
     *
     * 	    protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
     * 		    this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
     *      }
     * } */

    /* public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
     * } */

    /* public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
     *      public void setBeanFactory(BeanFactory beanFactory) {
     * 		    this.beanFactory = beanFactory;
     *      }
     *
     *      public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
     * 		    Object cacheKey = getCacheKey(beanClass, beanName);
     *
     * 		    if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
     * 			    if (this.advisedBeans.containsKey(cacheKey)) {
     * 				    return null;
     *              }
     *
     * 			    if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
     * 				    this.advisedBeans.put(cacheKey, Boolean.FALSE);
     * 				    return null;
     *              }
     *          }
     *
     * 		    // Create proxy here if we have a custom TargetSource.
     * 		    // Suppresses unnecessary default instantiation of the target bean:
     * 		    // The TargetSource will handle target instances in a custom fashion.
     * 		    TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
     * 		    if (targetSource != null) {
     * 			    if (StringUtils.hasLength(beanName)) {
     * 				    this.targetSourcedBeans.add(beanName);
     *              }
     *
     * 			    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
     * 			    Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
     * 			    this.proxyTypes.put(cacheKey, proxy.getClass());
     * 			    return proxy;
     *          }
     *
     * 		    return null;
     *      }
     *
     *      public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
     * 		    if (bean != null) {
     * 			    Object cacheKey = getCacheKey(bean.getClass(), beanName);
     * 			    if (!this.earlyProxyReferences.contains(cacheKey)) {
     * 				    return wrapIfNecessary(bean, beanName, cacheKey);
     *              }
     *          }
     *
     * 		    return bean;
     *      }
     * } */

    @Bean
    public LogAspect logAspect() {
        return new LogAspect();
    }

}
